<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <!-- Meta, title, CSS, favicons, etc. -->
    <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="文档管理">
<meta name="author" content="文档管理">
<title>开发指南 文档管理</title>
<link href="./assets/css/bootstrap.min.css" rel="stylesheet">
<!-- Documentation extras -->
<link href="./assets/css/docs.css" rel="stylesheet">
<link href="./assets/css/style.css" rel="stylesheet">
<link href="http://cdn.bootcss.com/highlight.js/7.3/styles/github.min.css" rel="stylesheet">
<style>
body{font-family:"ff-tisa-web-pro-1","ff-tisa-web-pro-2","Lucida Grande","Helvetica Neue",Helvetica,Arial,"Hiragino Sans GB","Hiragino Sans GB W3","WenQuanYi Micro Hei",sans-serif;}
h1, .h1, h2, .h2, h3, .h3, h4, .h4, .lead {font-family:"ff-tisa-web-pro-1","ff-tisa-web-pro-2","Lucida Grande","Helvetica Neue",Helvetica,Arial,"Hiragino Sans GB","Hiragino Sans GB W3","Microsoft YaHei UI","Microsoft YaHei","WenQuanYi Micro Hei",sans-serif;}
pre code { background: transparent; }
@media (min-width: 768px) {
    .bs-docs-home .bs-social, 
    .bs-docs-home .bs-masthead-links {
      margin-left: 0;
    }
}
.bs-docs-section p {
	line-height: 2;
}
.bs-docs-section p.lead {
	line-height: 1.4;
}
</style>
<!--[if lt IE 9]><script src="../docs-assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
  <script src="http://cdn.bootcss.com/html5shiv/3.7.0/html5shiv.min.js"></script>
  <script src="http://cdn.bootcss.com/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
<!-- Favicons -->
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="../docs-assets/ico/apple-touch-icon-144-precomposed.png">
<link rel="shortcut icon" href="../docs-assets/ico/favicon.png">
  </head>
  <body>
    <a class="sr-only" href="#content">Skip to main content</a>

    <!-- Docs master nav -->
    <header class="navbar navbar-inverse navbar-fixed-top bs-docs-nav" role="banner">
  <div class="container">
    <div class="navbar-header">
      <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".bs-navbar-collapse">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a href="./overview.html" class="navbar-brand">文档管理</a>
    </div>
    <nav class="collapse navbar-collapse bs-navbar-collapse" role="navigation">
      <ul class="nav navbar-nav">
       		<li  ><a href="overview.html">简介</a></li>
            <li ><a href="download.html">下载</a></li>
            <li class='active'><a href="userguide.html" class="selected">开发指南</a></li>
            <li ><a href="config.html">配置指南</a></li>
            <li ><a href="syntax.html">语法指南</a></li>
            <li ><a href="integrate.html">Web 框架集成</a></li>
            <!--
            <li ><a href="example.html">例子</a></li>
            -->
            <li ><a href="faq.html">FAQ</a></li>
            <li ><a href="about.html">关于</a></li>
      </ul>
    </nav>
  </div>
</header>
    <!-- Docs page layout -->
    <div class="bs-header" id="content">
      <div class="container">
        <h2>开发指南</h2>
        <p></p>
      </div>
    </div>
	<a href="#top" id="toTop"></a>
    <!-- Callout for the old docs link -->
    <div class="container bs-docs-container">
      <div class="row">
        <div class="col-md-3">
          <div class="bs-sidebar hidden-print" role="complementary">
            <ul class="nav bs-sidenav">
            <li><a href="#x1217142286">1 从这里开始 Start</a></li>
            <li><a href="#x1102343160">&nbsp&nbsp1.1 基本步骤 Steps</a></li>
            <li><a href="#x987989908">2 核心对象 Core</a></li>
            <li><a href="#x1273924123">&nbsp&nbsp2.1 JetEngine</a></li>
            <li><a href="#x1328335379">&nbsp&nbsp2.2 JetTemplate</a></li>
            <li><a href="#x902651658">&nbsp&nbsp2.3 JetContext</a></li>
            <li><a href="#x1213031356">3 高级用法</a></li>
            <li><a href="#x1112662598">&nbsp&nbsp3.1 方法扩展 Methods</a></li>
            <li><a href="#x829850106">&nbsp&nbsp3.2 函数扩展 Functions</a></li>
            <li><a href="#x1006401815">&nbsp&nbsp3.3 自定义标签 Tags</a></li>
            <li><a href="#x1633230618">4 错误处理 Finding Issue</a></li>
            <li><a href="#x521147885">&nbsp&nbsp4.1 语法错误 Syntax Error</a></li>
            <li><a href="#x1307151980">&nbsp&nbsp4.2 编译错误 Compile Error</a></li>
            <li><a href="#x689633529">&nbsp&nbsp4.3 运行期错误 Runtime Error</a></li>
            <li><a href="#x545437655">&nbsp&nbsp4.4 如何调试模板 debug？</a></li>
            </ul>
          </div>
        </div>
	        <div class="col-md-9" role="main">
	         <div class="bs-docs-section">
	           <h1 id="x1217142286" class="page-header"><span>1 从这里开始 Start</span></h1>
<h2 id="x1102343160" class="page-header"><span>1.1 基本步骤 Steps</span></h2> 
<ol> 
 <li>创建自定义配置的 <code>JetEngine</code> 对象。推荐使用单例模式创建。</li> 
 <li>根据模板路径，获取一个模板对象 <code>JetTemplate</code>。</li> 
 <li>创建一个 <code>Map&lt;String, Object&gt;</code> 对象，并加入你的 data objects。</li> 
 <li>准备一个待输出的对象，<code>OutputStream</code> 或者 <code>Writer</code>。</li> 
 <li>根据你的 data objects 来渲染模板，并获得输出结果。</li> 
</ol>
<p>具体的 Java 代码，看上去是这样的：</p> 
<div class="highlight">
 <pre><code class="language-html">// 创建一个默认的 JetEngine
JetEngine engine = JetEngine.create(); 

// 获取一个模板对象
JetTemplate template = engine.getTemplate(&quot;/sample.jetx&quot;);

// 创建 context 对象
Map&lt;String, Object&gt; context = new HashMap&lt;String, Object&gt;();
context.put(&quot;user&quot;, user);
context.put(&quot;books&quot;, books);

// 渲染模板
StringWriter writer = new StringWriter();
template.render(context, writer);

// 打印结果
System.out.println(writer.toString());
</code></pre>
</div>
<p>整个过程，是不是非常简单？</p>
<p>下面将介绍几个 API 的核心对象：<code>JetEngine</code>，<code>JetTemplate</code>，<code>JetContext</code> </p>
<h1 id="x987989908" class="page-header"><span>2 核心对象 Core</span></h1>
<h2 id="x1273924123" class="page-header"><span>2.1 JetEngine</span></h2>
<p>整个模板引擎的由 <code>JetEngine</code> 驱动，不同的 <code>JetEngine</code> 对象可以使用不同的配置。一般在一个 Application 或者 Webapp 中，我们只需要一个 <code>JetEngine</code> 对象就可以了，我们推荐使用单例模式创建。</p>
<h3 id="x97387442" class="page-header"><span>2.1.1 如何创建 JetEngine？</span></h3> 
<ol> 
 <li><p><code>JetEngine.create()</code></p><p>在 classpath 根目录下面自动查找 <code>jetbrick-template.properties</code> 文件。如果文件不存在，则使用默认配置。</p></li> 
 <li><p><code>JetEngine.create(File)</code></p><p>从用户指定的 <code>File</code> 文件中加载系统配置，该文件必须是一个 <code>.properties</code> 文件。</p></li> 
 <li><p><code>JetEngine.create(Properties)</code></p><p>从用户指定的 <code>Properties</code> 对象中加载系统配置。</p></li> 
</ol>
<p>有哪些配置？ <a href="config.html">看这里所有的配置</a></p>
<h3 id="x1502610422" class="page-header"><span>2.1.2 获取 JetTemplate 对象</span></h3>
<p>通过下面的方法获取 <code>JetTemplate</code> 对象。</p> 
<div class="highlight">
 <pre><code class="language-html">public JetTemplate getTemplate(String name) throws ResourceNotFoundException;
</code></pre>
</div>
<p>我们也可以获得一个 <code>Resource</code> （模板文件或者非模板文件），或者判断一个 <code>Resource</code> 是否存在。</p> 
<div class="highlight">
 <pre><code class="language-html">public boolean lookupResource(String name);
public Resource getResource(String name) throws ResourceNotFoundException;
</code></pre>
</div> 
<blockquote>
 <p><strong>注意</strong>：对于一个 resource 或者 template 的 name，应该以 <code>/</code> 开头，并且以 <code>/</code> 作为分隔符，如：<code>/templates/index.jetx</code>。</p> 
</blockquote>
<h3 id="x933655172" class="page-header"><span>2.1.3 从源码中直接创建模板</span></h3> 
<div class="highlight">
 <pre><code class="language-html">public JetTemplate createTemplate(String source);
</code></pre>
</div>
<p>比如：</p> 
<div class="highlight">
 <pre><code class="language-html">JetTemplate template = engine.createTemplate(&quot;${1+2*3}&quot;);
UnsafeCharArrayWriter out = new UnsafeCharArrayWriter();
template.render(new JetContext(), out);
Assert.assertEquals(&quot;7&quot;, out.toString());
</code></pre>
</div>
<p>注意： createTemplate() 每次都会编译生成新的 JetTemplate 对象，如果需要缓存，请自行维护。</p>
<h2 id="x1328335379" class="page-header"><span>2.2 JetTemplate</span></h2>
<p>对应于一个模板文件，通过 <code>JetEngine.getTemplate(name)</code> 获取。在第一次获取的时候，会先将模板生成对象的 <code>.java</code> 文件，然后在将 <code>.java</code> 文件编译成 <code>.class</code> 文件。</p>
<p>如果模板不存在，则抛出 <code>ResourceNotFoundException</code>。</p>
<p>然后通过下面几个方法可以对模板进行渲染：</p> 
<div class="highlight">
 <pre><code class="language-html">public void render(Map&lt;String, Object&gt; context, Writer out);
public void render(Map&lt;String, Object&gt; context, OutputStream out);
public void render(JetContext context, Writer out);
public void render(JetContext context, OutputStream out);
</code></pre>
</div>
<p>我们可以使用 <code>Map&lt;String, Object&gt;</code> 或者 <code>JetContext</code> 存储我们的 data objects。<code>JetContext</code> 是对 <code>Map&lt;String, Object&gt;</code> 的简单封装。</p> 
<blockquote>
 <p><strong>注意</strong>： </p> 
 <ul> 
  <li><code>context</code> 对象在模板运行期间，并不会受到模板污染，即数据不会被改变（保证数据的无侵入性）。</li> 
 </ul> 
</blockquote>
<h2 id="x902651658" class="page-header"><span>2.3 JetContext</span></h2>
<p>用来存储和获取模板关联的 data objects。可以通过 <code>new JetContext()</code> 或者 <code>new JetContext(map)</code> 创建。</p>
<p>使用 <code>JetContext</code> 就像使用 Java 的 <code>HashMap</code> 一样。常用的方法如下：</p> 
<div class="highlight">
 <pre><code class="language-html">public Object get(String name);
public void put(String name, Object value);
public void putAll(Map&lt;String, Object&gt; context);
</code></pre>
</div> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li><code>JetContext</code> 会被 <code>#put</code> 指令修改</li> 
  <li>用户提供的 <code>JetContext</code> 不会受到 <code>#set</code> 的影响，但是内部的使用的 <code>JetContext</code> 对象会受到 <code>#set</code> 指令的影响。</li> 
  <li><code>JetContext</code> 会在父子模板调用的时候，形成一个 Context Chain，子模板可以自动获取父模板的变量，而父模板无法看到子模板的 <code>JetContext</code>。但是子模板可以通过 <code>#put(name, value)</code> 来修改父模板的 <code>JetContext</code>。具体查看：<a href="faq-include.html">如何嵌入子模板？</a></li> 
 </ul> 
</blockquote>
<h1 id="x1213031356" class="page-header"><span>3 高级用法</span></h1>
<p>上面只是简单的介绍了一下 <code>jetbrick-template</code> 的基本用法，下面将介绍一些高级用法，也是 <code>jetbrick-template</code> 有别于其他模板引擎的特色。</p>
<p><a name="methods"></a></p>
<h2 id="x1112662598" class="page-header"><span>3.1 方法扩展 Methods</span></h2>
<p>我们知道一个 Java Class 的 所有 methods 都是定义在同一个 class 文件中的，不能在其他地方进行动态扩展。但是一些其他动态语言却支持在 Class 外部为这个 Class 增加一些方法。比如：</p> 
<ul> 
 <li>JavaScript 的 prototype 机制</li> 
 <li>Groovy 的 metaClass 机制</li> 
 <li>JetBrains 的 Kotlin</li> 
</ul>
<p>jetbrick-template 也在这里带给大家强大的动态方法扩展机制。如：<code>&quot;123&quot;.asInt()</code>, <code>new Date().format(&quot;yyyy-MM-dd&quot;)</code>。</p> 
<blockquote>
 <p><strong>注意</strong>：如果 Class 已经定义了同名方法，则优先使用 Class 定义的方法。但是扩展方法支持方法重载(Overrload)。</p> 
</blockquote>
<p>方法扩展支持 2 种模式：</p> 
<ul> 
 <li>上下文无关方法：MethodTool.method(bean, ...)</li> 
 <li>上下文相关方法：MethodTool.method(bean, JetPageContext, ...)</li> 
</ul>
<h3 id="x364359324" class="page-header"><span>3.1.1 上下文无关方法 MethodTool.method(bean, ...)</span></h3> 
<ul> 
 <li>方法签名必须是 <code>public</code> 和 <code>static</code></li> 
 <li>方法的第一个参数类型必须是要扩展的 Class</li> 
 <li>方法其余参数自定义</li> 
</ul>
<p>示例：对 <code>String</code> 进行扩展</p> 
<div class="highlight">
 <pre><code class="language-html">public class StringMethods {
  public static String link(String text, String url) {
    return &quot;&lt;a href=\&quot;&quot; - url - &quot;\&quot;&gt;&quot; - text - &quot;&lt;/a&gt;&quot;;
  }
}
</code></pre>
</div>
<p>然后需要把扩展的 <code>StringMethods</code> 注册到 <code>JetEngine</code>。</p> 
<div class="highlight">
 <pre><code class="language-html">// 把 StringMethods 加入到 engine 中
Properties config = new Properties();
config.put(JetConfig.IMPORT_METHODS, StringMethods.class.getName());
JetEngine engine = JetEngine.create(config);
...
</code></pre>
</div>
<p>模板：</p> 
<div class="highlight">
 <pre><code class="language-html">${&quot;BAIDU&quot;.link(&quot;http://www.baidu.com/&quot;)}
</code></pre>
</div>
<p>输出结果：</p> 
<div class="highlight">
 <pre><code class="language-html">&lt;a href=&quot;http://www.baidu.com/&quot;&gt;BAIDU&lt;/a&gt;
</code></pre>
</div>
<h3 id="x1425351729" class="page-header"><span>3.1.2 上下文相关方法 MethodTool.method(bean, JetPageContext, ...)</span></h3>
<p>如果扩展的方法需要用到 template 相关联的运行时信息 <code>JetPageContext</code>，那么我们就需要扩展一个上下文相关的 method。</p>
<p>和上下文无关的扩展方法相比，上下文相关的扩展方法多一个参数。</p> 
<ul> 
 <li>方法签名必须是 <code>public</code> 和 <code>static</code></li> 
 <li>方法第一个参数类型是要扩展的 Class</li> 
 <li><strong>方法第二个参数类型必须是 JetPageContext</strong></li> 
 <li>方法其余参数自定义</li> 
</ul> 
<div class="highlight">
 <pre><code class="language-html">public class UserInfoMethods {
	public static String isOnline(UserInfo user, JetPageContext ctx) {
    	HttpSession session = (HttpSession) ctx.getContext().get(JetContext.SESSION_NAME);
    	return session.getAttribute(&quot;user_&quot; - user.getName()) != null;
  	}
}
 
// 把 UserInfoMethods 加入到 engine 中
Properties config = new Properties();
config.put(JetConfig.IMPORT_METHODS, UserInfoMethods.class.getName());
JetEngine engine = JetEngine.create(config);
...
</code></pre>
</div>
<p>模板：</p> 
<div class="highlight">
 <pre><code class="language-html">#define(UserInfo user)
${user.isOnline()}
</code></pre>
</div>
<p><a name="functions"></a></p>
<h2 id="x829850106" class="page-header"><span>3.2 函数扩展 Functions</span></h2>
<p>jetbrick-template 还支持函数扩展，如 <code>${now()}</code>, <code>${include(&quot;tag.jetx&quot;)}</code>。</p> 
<ul> 
 <li>上下文无关函数：任意参数</li> 
 <li>上下文相关函数：第一个参数必须是 JetPageContext</li> 
</ul>
<p>示例：</p> 
<div class="highlight">
 <pre><code class="language-html">public class Functions {
  // 上下文无关函数
  public static String today(String format) {
    return new SimpleDateFormat(format).format(new Date());
  }
  // 上下文相关函数
  public static String hello(JetPageContext ctx) {
    return &quot;Hello &quot; - ctx.getContext().get(&quot;name&quot;);
  }
}

// 把 Functions 加入到 engine 中
Properties config = new Properties();
config.put(JetConfig.IMPORT_FUNCTIONS, Functions.class.getName());
JetEngine engine = JetEngine.create(config);
...

</code></pre>
</div>
<p>模板：</p> 
<div class="highlight">
 <pre><code class="language-html">${today(&quot;yyyy-MM-dd&quot;)}
${hello()}
</code></pre>
</div> 
<blockquote>
 <p><strong>注意</strong>：函数和扩展方法的唯一区别是少了第一个扩展类型的参数，其他的都一样。</p> 
</blockquote>
<p><a name="tags"></a></p>
<h2 id="x1006401815" class="page-header"><span>3.3 自定义标签 Tags</span></h2>
<p>jetbrick-template 自定义标签 Tag，类似于 JSP Taglib，但是要比 JSP Taglib 更简单更好用。</p>
<p>示例：</p> 
<div class="highlight">
 <pre><code class="language-html">public class Tags {
  public static void cache(JetTagContext ctx, String name, int timeout) throws IOException {
    Cache cache = CacheManager.getCache(); // 请用自己的 Cache 代替
    Object value = cache.get(name);
    if (value == null) {
      value = ctx.getBodyContext();
      cache.put(name, value, timeout);
    }
    ctx.getWriter().print(value);
  }
}
</code></pre>
</div>
<p>对于每一个 Tag 的方法声明，有如下要求：</p> 
<ul> 
 <li>方法签名必须是 <code>public</code> <code>static</code></li> 
 <li>方法返回值必须是 <code>void</code></li> 
 <li>方法第一个参数必须是 <code>JetTagContext</code>， 其余参数自定义</li> 
 <li>允许 throws 任意的 <code>Throwable</code></li> 
 <li>允许定义相同名字的 Tag，但是方法参数不一样 （Overload）</li> 
 <li>支持可变参数 (VarArgs)</li> 
</ul>
<p>然后需要把自定义的 Tags 注册到 <code>JetEngine</code>。</p> 
<div class="highlight">
 <pre><code class="language-html">// 把 Tags 加入到 engine 中
Properties config = new Properties();
config.put(JetConfig.IMPORT_TAGS, Tags.class.getName());
JetEngine engine = JetEngine.create(config);
...
</code></pre>
</div>
<p>模板：</p> 
<div class="highlight">
 <pre><code class="language-html">#tag cache(&quot;sum&quot;, 10)
    计算结果将被缓存10秒： ${1+2+3+4+5+6+7+8+9}
#end
</code></pre>
</div>
<p>具体可以参考：<a href="faq-tag.html">jetbrick-template 中如何自定义 Tag？</a></p>
<h1 id="x1633230618" class="page-header"><span>4 错误处理 Finding Issue</span></h1>
<p><code>jetbrick-template</code> 提供了强大的错误定位功能，你再也不用担心找不到错误原因了。</p>
<h2 id="x521147885" class="page-header"><span>4.1 语法错误 Syntax Error</span></h2>
<p>模板示例：</p> 
<div class="highlight">
 <pre><code class="language-html">#for (user in userlist)
&lt;tr&gt;
    &lt;td&gt;${for.index}&lt;/td&gt;
    &lt;td&gt;${user.name}&lt;/td&gt;
    &lt;td&gt;${user.roles.asHTML()}&lt;/td&gt;
&lt;/tr&gt;
#end
</code></pre>
</div>
<p>错误提示：(错误所在的行号和列号，错误模板路径，错误原因等）</p> 
<div class="highlight">
 <pre><code class="language-html">22:14:51.406 [main] ERROR (JetTemplateErrorListener.java:27) - Template parse failed:
C:\Users\Sub\AppData\Local\Temp\jetx_1_0_0\template\sample.java:5
message: The method asHTML() is undefined for the type List.
1. #for (user: userlist)
2. &lt;tr&gt;
3.     &lt;td&gt;${for.index}&lt;/td&gt;
4.     &lt;td&gt;${user.name}&lt;/td&gt;
5.     &lt;td&gt;${user.roles.asHTML()}&lt;/td&gt;
                        ^^^^^^
</code></pre>
</div>
<h2 id="x1307151980" class="page-header"><span>4.2 编译错误 Compile Error</span></h2>
<p>这种错误正常情况下是不会发生的，如果发生这种情况，<a href="https://github.com/subchen/jetbrick-template/issues/">请到这里 open issues</a>。</p>
<p>但是如果发生这样的错误，也可以得到下面的类似错误提示。</p> 
<div class="highlight">
 <pre><code class="language-html">Exception in thread &quot;main&quot; java.lang.IllegalStateException: Compilation failed.
C:\Users\Sub\AppData\Local\Temp\jetx_1_0_0\template\debug_jetx.java:13: 'void' type not allowed here
  11:     JetWriter $out = $ctx.getWriter();
  12:     JetContext context = $ctx.getContext();
  13:     $out.print((&quot;1&quot;+JetFunctions.debug(&quot;aaa&quot;))); // line: 1
                      ^
1 error(s)
</code></pre>
</div>
<p>我们可以从打印出来的编译错误中，可以看到大部分源代码后面都会有一个 <code>// line: XXX</code> 的注释，这个就是生成的 java 代码对应原始模板文件的行号映射。这样我们就能找到原始模板的错误行数了。</p>
<p>模板示例：</p> 
<div class="highlight">
 <pre><code class="language-html">1: ${&quot;1&quot;+debug(&quot;aaa&quot;)}
</code></pre>
</div>
<p>生成的 Java 代码示例：</p> 
<div class="highlight">
 <pre><code class="language-html">$out.print((&quot;1&quot;+JetFunctions.debug(&quot;aaa&quot;))); // line: 1
</code></pre>
</div>
<h2 id="x689633529" class="page-header"><span>4.3 运行期错误 Runtime Error</span></h2>
<p>如果在模板运行期间发生错误，那么就可以得到类似下面的错误 Java Exception Stack。</p>
<p>错误例子模板如下：</p> 
<div class="highlight">
 <pre><code class="language-html">#set (arraylist = [&quot;a&quot;,&quot;b&quot;,&quot;c&quot;,&quot;d&quot;])
#for (int x : arraylist)
    ${x}
#end
</code></pre>
</div>
<p>获得的运行期错误 Java Exception Stack 如下：</p> 
<div class="highlight">
 <pre><code class="language-html">generateJavaClass: C:\Users\Sub\AppData\Local\Temp\jetx_1_0_0\template\for_loop_list_jetx.class
Exception in thread &quot;main&quot; java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
	at template.for_loop_list_jetx.render(for_loop_list_jetx.java:14)
	at jetbrick.template.JetTemplate.render(JetTemplate.java:125)
	at jetbrick.template.JetTemplate.render(JetTemplate.java:115)
	at testcase.JetEngineTestCase.test(JetEngineTestCase.java:36)
	at testcase.JetEngineTestCase.main(JetEngineTestCase.java:64)
</code></pre>
</div>
<p>根据错误所在行(for_loop_list_jetx.java:14)，我们查看生成的 Java Source。</p> 
<div class="highlight">
 <pre><code class="language-html">11:    List arraylist = (List) Arrays.asList(&quot;a&quot;,&quot;b&quot;,&quot;c&quot;,&quot;d&quot;); // line: 1
12:    Iterator&lt;?&gt; $it_3 = JetUtils.asIterator(arraylist);
13:    while ($it_3.hasNext()) { // line: 2
14:      Integer x = (Integer) $it_3.next();
15:      $out.print($txt_4, $txt_4_bytes);
</code></pre>
</div>
<p>然后根据 Java Source 中对应的行数，知道这个是一个 <code>#for</code> 指令，查看生成的注释(<code>// line: 2</code>)，就能找到对应的原始模板所在的错误行号是第二行：<code>#for (int x : arraylist)</code>。</p>
<p>至此，我们就能知道错误的原因是 <code>arraylist</code> 是一个 <code>List&lt;Object&gt;</code>，里面的每个元素是 <code>String</code>，强制类型转换成 <code>int</code> 失败导致的。正确的模板语句应该是 <code>#for (String x : arraylist)</code>。</p>
<p><a name="debug"></a></p>
<h2 id="x545437655" class="page-header"><span>4.4 如何调试模板 debug？</span></h2>
<h3 id="x1051770788" class="page-header"><span>4.4.1 使用 debug(format, args...) 函数</span></h3>
<p>范例：</p> 
<div class="highlight">
 <pre><code class="language-html">${debug(&quot;id = {}, users.size = {}.&quot;, id, users.size()}
</code></pre>
</div> 
<blockquote>
 <p>注意： </p> 
 <ol> 
  <li><p>要使用 debug 函数，需要 Slf4j 配合，在对应的 log 实现中打开 debug.</p></li> 
  <li><p>具体的 format 参数格式请查看 <a href="http://www.slf4j.org/apidocs/org/slf4j/Logger.html">Slf4j Logger</a>。</p></li> 
 </ol> 
</blockquote>
<p>开启 debug 日志：</p> 
<ul> 
 <li><p>Log4j:</p> 
  <div class="highlight">
   <pre><code class="language-html">log4j.logger.jetbrick.template.runtime.JetUtils = DEBUG
</code></pre>
  </div></li> 
 <li><p>Logback</p> 
  <div class="highlight">
   <pre><code class="language-html">&lt;logger name=&quot;jetbrick.template.runtime.JetUtils&quot; level=&quot;DEBUG&quot; /&gt;
</code></pre>
  </div></li> 
</ul>
<h3 id="x638605844" class="page-header"><span>4.4.2 用 Eclipse 进行调试</span></h3> 
<ol> 
 <li><p>将模板编译路径连接到 Project 的 source path</p><p><img src="../assets/images/screen_link_source.png" alt="png" /></p></li> 
 <li><p>设置断点 </p><p><img src="../assets/images/screen_set_breakpoint.png" alt="png" /></p></li> 
 <li><p>开始 debug</p><p><img src="../assets/images/screen_debug.png" alt="png" /></p></li> 
</ol>
           	</div>
           </div>
		</div> 
 	</div>
    <!-- Footer
    ================================================== -->
    <footer class="bs-footer" role="contentinfo">
      <div class="container">
        <ul class="footer-links">
          <li>当前版本： v0.0.3</li>
          <li class="muted">&middot;</li>
          <li><a href="http://v2.bootcss.com/">Bootstrap 2.3.2 中文文档</a></li>
          <li class="muted">&middot;</li>
          <li><a href="http://www.bootcss.com">Bootstrap中文网</a></li>
          <li class="muted">&middot;</li>
          <li><a href="http://blog.getbootstrap.com">官方博客</a></li>
          <li class="muted">&middot;</li>
          <li><a href="https://github.com/twbs/bootstrap/issues?state=open">Issues</a></li>
          <li class="muted">&middot;</li>
          <li><a href="https://github.com/twbs/bootstrap/releases">Releases</a></li>
        </ul>
      </div>
    </footer>

    <!-- JS and analytics only. -->
<script src="http://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>
<script src="./assets/js/bootstrap.js"></script>
<script src="http://cdn.bootcss.com/holder/2.0/holder.min.js"></script>
<script src="http://cdn.bootcss.com/highlight.js/7.3/highlight.min.js"></script>
<script >hljs.initHighlightingOnLoad();</script>
<script src="./assets/js/application.js"></script>
<script src="./assets/js/jquery.scrollToTop.min.js"></script>
<script text="javascript/text">
	$(document).ready(function(){
		$("#toTop").scrollToTop(1000);
  		$("table").addClass("table table-bordered");
  	});
</script>
  </body>
</html>
